package sg.edu.nus.iss.vmcs.store;

import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
import sg.edu.nus.iss.vmcs.util.IObservable;
import sg.edu.nus.iss.vmcs.util.IObserver;
import sg.edu.nus.iss.vmcs.abstraction.IStoreFactory;
import sg.edu.nus.iss.vmcs.abstraction.IStoreService;
import sg.edu.nus.iss.vmcs.util.VMCSException;

/**
 * @author Kyaw Soe Ya
 * 
 */
public class StoreService implements IStoreService
{
	private CashStore cashStore;
	private DrinksStore drinkStore;

	private HashMap<IObservable, Vector<IObserver>> subjectMapping;

	public StoreService(IStoreFactory storeFactory) throws VMCSException
	{
		cashStore = (CashStore) storeFactory.createStore(Store.CASH);
		drinkStore = (DrinksStore) storeFactory.createStore(Store.DRINK);
	}

	public void storeCoin(Coin c)
	{
		int idx = cashStore.findCashStoreIndex(c);
		CashStoreItem item;
		item = (CashStoreItem) this.getStoreItem(Store.CASH, idx);
		if(item!=null)
		    item.increment();
	}

	public int getStoreSize(int type)
	{
		if (type == Store.CASH)
			return cashStore.getStoreSize();
		else
			return drinkStore.getStoreSize();
	}

	public StoreItem[] getStoreItems(int type)
	{
		if (type == Store.CASH)
			return cashStore.getItems();
		else
			return drinkStore.getItems();
	}

	public void changeStoreQty(int type, int idx, int qty)
	{
		System.out.println("StoreController.changeStoreQty: type:" + type
				+ "   qty:" + qty);
		if (type == Store.CASH)
			cashStore.setQuantity(idx, qty);
		else
			drinkStore.setQuantity(idx, qty);
	}

	public StoreItem getStoreItem(int type, int idx)
	{
		if (type == Store.CASH)
			return cashStore.getStoreItem(idx);
		else
			return drinkStore.getStoreItem(idx);
	}

	public void setPrice(int idx, int pr)
	{
		DrinksStoreItem item;

		item = (DrinksStoreItem) drinkStore.getStoreItem(idx);
		DrinksBrand bd;

		bd = (DrinksBrand) item.getContent();

		bd.setPrice(pr);
	}
	
	/*
	 * @author khaing zar maung
	 */
	public int getTotalCash()
	{
		CashStoreItem item;
		int qty;
		int val;
		int tc = 0;
		Coin c;
		
		// apply iterator
		Iterator itr = cashStore.createIterator(Store.NONZERO);
		while(itr.hasNext()){
			item = (CashStoreItem)itr.next();
			c = (Coin) item.getContent();
			
			qty = item.getQuantity();			
			val = c.getValue();
			tc = tc + qty * val;
		}
		return tc;		
	}

	public int transferAll()
	{
		int i;
		int cc = 0; // coin quantity;
		int size = cashStore.getStoreSize();

		CashStoreItem item;
		for (i = 0; i < size; i++)
		{
			item = (CashStoreItem) cashStore.getStoreItem(i);
			cc = cc + item.getQuantity();
			item.setQuantity(0);
		}

		return cc;
	}

	public void closeDown() throws IOException
	{
		// save back cash property;
		saveCashProperties();
		saveDrinksProperties();
	}

	private void saveCashProperties() throws IOException
	{
		this.cashStore.saveProperty();
	}

	/*
	 * save the drink property when simulation is ended.
	 */
	private void saveDrinksProperties() throws IOException
	{
		this.drinkStore.saveProperty();
	}

	public void dispenseDrink(int idx)
	{
		DrinksStoreItem item;
		item = (DrinksStoreItem) getStoreItem(Store.DRINK, idx);
		item.decrement();
	}

	public Store getStore(int type)
	{
		if (type == Store.CASH)
			return (Store) cashStore;
		else
			return (Store) drinkStore;
	}

	public void giveChange(int idx, int numOfCoins)
	{
		CashStoreItem item;
		item = (CashStoreItem) getStoreItem(Store.CASH, idx);
		for (int i = 0; i < numOfCoins; i++)
			item.decrement();
	}

	/**
	 * Observer pattern changes start from here
	 */
	public void register(IObservable observable, IObserver observer)
	{

		if (subjectMapping == null)
		{
			subjectMapping = new HashMap<IObservable, Vector<IObserver>>();
		}
		if (subjectMapping.containsKey(observable))
		{
			Vector<IObserver> observers = subjectMapping.get(observable);
			observers.add(observer);
			subjectMapping.remove(observable);
			subjectMapping.put(observable, observers);
		} else
		{
			Vector<IObserver> observers = new Vector<IObserver>();
			observers.add(observer);
			subjectMapping.put(observable, observers);
		}
	}

	public void unRegister(IObservable observable, IObserver observer)
	{
		if (subjectMapping != null)
		{
			if (subjectMapping.containsKey(observable))
			{
				Vector<IObserver> observers = subjectMapping.get(observable);
				if (observers.contains(observer))
				{
					observers.remove(observer);
				}
				subjectMapping.remove(observable);
				subjectMapping.put(observable, observers);
			}
		}
	}

	public void notifyObservers(IObservable observable)
	{
		System.out.println("notify observers: ");
		if (subjectMapping != null)
		{

			if (subjectMapping.containsKey(observable))
			{

				Vector<IObserver> observers = subjectMapping.get(observable);
				for (IObserver observer : observers)
				{

					observer.update(observable);
				}
			}
		}
	}

}
